package c2.advanced.business.common.mail;

import c2.advanced.business.base.AdvancedSubModule;
import cate.common.game.mail.MailCmd;
import cate.common.rpc.path.RpcCommonPath;
import cp.solution.pattern.Result;
import lombok.extern.slf4j.Slf4j;

import java.util.*;
import java.util.concurrent.locks.ReentrantLock;

/** 确保按要求发送
 * 目前是一个简易版本的实现, 有空的时候完善*/
@Slf4j
public class MailPostBox extends AdvancedSubModule {

    private ReentrantLock ll = new ReentrantLock(false);
    private List<MailCmd> list = new ArrayList<>();

    public void add(MailCmd cmd) {
        try {
            this.ll.lock();
            removeSent();
            sortTT();
            this.list.add(cmd);
        }  catch (Exception e) {
            log.error("", e);
        } finally {
            this.ll.unlock();
        }
    }

    public void addList(List<MailCmd> cmds) {
        try {
            this.ll.lock();
            removeSent();
            sortTT();
            this.list.addAll(cmds);
        }  catch (Exception e) {
            log.error("", e);
        } finally {
            this.ll.unlock();
        }
    }

    private void removeSent() {
        int nDel = 0;
        Iterator<MailCmd> iter = this.list.iterator();
        while(iter.hasNext()) {
            MailCmd cmd = iter.next();
            if(cmd.hasBeenSent()) {
                iter.remove();
                nDel++;
            }
        }
        if(nDel > 0) {
            log.info("移除了{}条已经发送成功的邮件指令", nDel);
        }
    }

    private void sortTT() {
        this.list.sort(Comparator.comparingInt(MailCmd::tt));
    }

    private static final int BATCH_MAX = 100;

    Map<Integer, Long> failSrvLog = new HashMap<>(2);

    @Override
    public void onInterval() throws Exception {
        List<MailCmd> todos = null;
        try {
            this.ll.lock();
            if(this.list.isEmpty()) {
                return;
            }
            todos = new ArrayList<>();
            int curBatch = 0;
            for(MailCmd cmd : this.list) {
                if(cmd.hasBeenSent()) {
                    continue;
                }
                Long failTime = failSrvLog.get(cmd.srvId);
                if(failTime != null) {
                    if(System.currentTimeMillis() - failTime > 60_000) {
                        log.info("因为距离上次发邮件给游戏服{}失败已过去一段时间了，因此可以再试一下", cmd.srvId);
                        failSrvLog.remove(cmd.srvId);
                    } else {
                        continue;
                    }
                }
                cmd.tt++;
                curBatch++;
                todos.add(cmd);
                if(curBatch >= BATCH_MAX) {
                    break;
                }
            }
        } catch (Exception e) {
            log.error("", e);
        } finally {
            this.ll.unlock();
        }
        //
        try {
            Set<Integer> _failSrvIds = new HashSet<>(1);
            for(MailCmd cmd : todos) {
                try {
                    if(_failSrvIds.contains(cmd.srvId)) {
                        continue;
                    }
                    Result er = useRpcSend().requestResponseGameTemplate(RpcCommonPath.MAIL_SEND_TO_GAME, cmd.srvId, cmd, Result.class);
                    if(er != null && er.ok()) {
                        cmd.sentTime = System.currentTimeMillis();
                    } else {
                        log.warn("发送邮件给游戏服{}失败：{}, er={}, 所以本轮发给该游戏服的邮件都取消发送", cmd.srvId, cmd, er);
                        _failSrvIds.add(cmd.srvId);
                        failSrvLog.put(cmd.srvId, System.currentTimeMillis());
                    }
                } catch (Exception e) {
                    log.error("发送邮件给游戏服{}失败 {} {}, 所以本轮发给该游戏服的邮件都取消发送", cmd.srvId, e.getClass(), e.getMessage());
                    _failSrvIds.add(cmd.srvId);
                    failSrvLog.put(cmd.srvId, System.currentTimeMillis());
                }
            }
        } catch (Exception e) {
            log.error("", e);
        }
    }
}
